pub mod db_role;
pub mod db_tag_relation;
pub mod db_tag;
pub mod db_user;
pub mod db_user_role;
pub mod define;
pub mod entities;
use log::{info, trace};

use anyhow::{Ok, Result};
use serde::Deserialize;

use crate::db::entities::role::RoleModel;
use crate::db::entities::user::UserModel;
use crate::db::entities::user_role::UserRoleModel;
use crate::utils::security_utils::create_password;

pub async fn init() -> Result<()> {
    db_user::init_tables().await?;
    db_user_role::init_tables().await?;
    db_role::init_tables().await?;
    db_tag_relation::init_tables().await?;
    db_tag::init_tables().await?;

    load_default_roles().await?;
    load_default_users().await?;

    Ok(())
}

#[derive(Debug, Deserialize)]
struct TempRole {
    pub name: String,
    pub role: String,
}
pub async fn load_default_roles() -> Result<()> {
    info!("Loading default roles");

    let input_json: &[u8] = include_bytes!("../../resources/roles.json");
    let roles: Vec<TempRole> = serde_json::from_slice(input_json)?;

    for role in roles {
        trace!("find role: {:?}", role);
        if db_role::find_by_role(&role.role).await?.is_some() {
            continue;
        }

        trace!("Inserting role: {:?}", role);
        let model = RoleModel {
            name: Some(role.name),
            role: Some(role.role),
            ..Default::default()
        };
        db_role::insert(model).await?;
    }

    Ok(())
}

#[derive(Debug, Deserialize)]
struct TempUser {
    pub name: String,
    pub login_name: String,
    pub password: String,
    pub role: String,
}
pub async fn load_default_users() -> Result<()> {
    info!("Loading default users");

    let input_json: &[u8] = include_bytes!("../../resources/users.json");
    let users: Vec<TempUser> = serde_json::from_slice(input_json)?;

    for user in users {
        trace!("find user login_name: {:?}", user.login_name);
        if db_user::find_by_login_name(&user.login_name).await?.is_some() {
            continue;
        }

        // role
        trace!("find user role: {:?}", user.role);
        let role_model = match db_role::find_by_role(&user.role).await? {
            Some(role) => role,
            None => {
                continue;
            }
        };

        // user
        trace!("Inserting user: {:?}", user);
        let (password, salt) = create_password(&user.password);
        let user_model = UserModel {
            name: Some(user.name),
            login_name: Some(user.login_name),
            password: Some(password),
            salt: Some(salt),
            ..Default::default()
        };
        let user_model = db_user::insert(user_model.clone()).await?;

        // user role 关系
        trace!("Inserting user role: {:?} {:?}", user_model.id, role_model.id);
        if db_user_role::find_by_user_id_and_role_id(user_model.id, role_model.id).await?.is_some() {
            continue;
        }
        let _ = db_user_role::insert_role(UserRoleModel {
            user_id: user_model.id,
            role_id: role_model.id,
            ..Default::default()
        })
        .await?;
    }

    Ok(())
}
